package com.tiger.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * word 生成工具类(保留原单元格样式)
 */
public class WordGenerateUtil {

    /**
     * <b>功能</b>：模板转换<br/>
     *
     * @param in  文件输入流
     * @param map 数据Map<String,Object> <br>
     *            例如：map.put("key1",String);//段落值<br>
     *            map.put("key2",List&ltMap&ltString,String&gt&gt cm)
     *            //表格对应的循环list;
     * @return 文件字节流
     */
    public static XWPFDocument TemplateTransfer(InputStream in,
                                                Map<String, Object> map) throws IOException {
        XWPFDocument document = new XWPFDocument(in);
        checkHead(document, map);
        checkParagraphs(document, map);
        checkTables(document, map);
        replaceInPara(document, map);
        replaceInTable(document, map);

        return document;
    }

    /**
     * 表单生成
     * @param in
     * @param map
     * @return
     * @throws IOException
     */
    public static XWPFDocument TemplateTransfer2(InputStream in,
                                                Map<String, Object> map) throws IOException {
        XWPFDocument document = new XWPFDocument(in);
        checkHead(document, map);
        checkParagraphs(document, map);
        checkTables2(document, map);
        return document;
    }

    /**
     * <b>功能</b>：处理模板页眉内容<br/>
     *
     * @param document XWPFDocument对象
     * @param map      数据源
     */
    private static void checkHead(XWPFDocument document, Map<String, Object> map) {
        List<XWPFParagraph> paragraphs = new ArrayList<XWPFParagraph>();
        // 取得页眉
        List<XWPFHeader> headerList = document.getHeaderList();
        // 取得页眉列表外段落
        if (com.tiger.common.utils.StringUtils.isNotEmpty(headerList)){
            List<XWPFParagraph> headerParas = headerList.get(0).getParagraphs();
            paragraphs.addAll(headerParas);
        }


        // 取得页眉列表内段落
        /*List<XWPFTable> tables = headerList.get(0).getTables();
        for (XWPFTable table : tables) {
            List<XWPFTableRow> rows = table.getRows();
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    paragraphs.addAll(cell.getParagraphs());
                }
            }
        }*/

        for (XWPFParagraph tmp : paragraphs) {
            List<XWPFRun> runs = tmp.getRuns();
            for (XWPFRun r : runs) {
                for (Entry<String, Object> e : map.entrySet()) {
                    if (StringUtils.isNotEmpty(r.getText(0))) {
                        if (r.getText(0).equals(e.getKey()) && r.isStrike()) {
                            r.setText((String) e.getValue(), 0);
                            r.setStrike(false);
                        }

                    }
                }
            }
        }


    }

    /**
     * <b>功能</b>：处理模板段落内容<br/>
     *
     * @param document XWPFDocument对象
     * @param map      数据源
     */
    public static void checkParagraphs(XWPFDocument document,
                                       Map<String, Object> map) {
        List<XWPFParagraph> listParagraphs = document.getParagraphs();

        for (XWPFParagraph tmp : listParagraphs) {
            List<XWPFRun> runs = tmp.getRuns();
            for (XWPFRun r : runs) {
                for (Entry<String, Object> e : map.entrySet()) {
                    if (StringUtils.isNotEmpty(r.getText(0))) {
                        if (r.getText(0).equals(e.getKey()) && r.isStrike()) {
                            r.setText((String) e.getValue(), 0);
                            r.setStrike(false);
                        }

                    }
                }
            }
        }
    }

    /**
     * <b>功能</b>：处理Word模板中Table内容<br/>
     *
     * @param document XWPFDocument对象
     * @param map      数据源
     */
    @SuppressWarnings("unchecked")
    public static void checkTables2(XWPFDocument document, Map<String, Object> map) {
        Iterator<XWPFTable> it = document.getTablesIterator();
        while (it.hasNext()) {
            XWPFTable table = (XWPFTable) it.next();
            int startRowIndex = 0;
            int rcount = table.getNumberOfRows();
            String key = "";
            List<String> arr = new ArrayList<String>();
            List<String> arrText = new ArrayList<String>();
            List<XWPFParagraph> paragraphsText = new ArrayList<XWPFParagraph>();
            List<XWPFTableCell> cellText = new ArrayList<XWPFTableCell>();

            //单元格中只取第一个段落
            List<XWPFParagraph> paragraphs = new ArrayList<XWPFParagraph>();
            for (int i = 0; i < rcount; i++) {
                XWPFTableRow row = table.getRow(i);
                List<XWPFTableCell> cells = row.getTableCells();

                for (XWPFTableCell cell : cells) {
                    if (cell.getText().indexOf("forEach") > -1) {
                        String find = "\\{(.*?)\\}";
                        key = getStrbyPattern(cell.getText(), find);
                        startRowIndex = i;
//                        if (map.containsKey(key)) {
//                            new XWPFTableRow(table.getCTTbl().addNewTr(), table);
//                        }
                        continue;
                    }

                    if (cell.getText().indexOf("#{") > -1) {
                        String find = "\\{" + key + ".(.*?)\\}";
                        String vCell = getStrbyPattern(cell.getText(), find);
                        paragraphs.add(cell.getParagraphs().get(0));
                        arr.add(vCell);
                    }

                    if (cell.getText().indexOf("${") > -1) {
                        cellText.add(cell);
                        paragraphsText.add(cell.getParagraphs().get(0));
                        arrText.add(cell.getText().replace("${", "").replace("}", ""));
                    }

                }
            }

            if (arrText.size() > 0) {
                for (int i = 0; i < arrText.size(); i++) {
                    XWPFParagraph xx = paragraphsText.get(i);
                    if (map.containsKey(arrText.get(i).toUpperCase())) {

                        List<XWPFParagraph> xwps = cellText.get(i).getParagraphs();
                        if (xwps.size() >= 1) {
                            for (XWPFParagraph x : xwps) {
                                int length = x.getRuns().size();
                                for (int s = (length - 1); s >= 0; s--) {
                                    x.removeRun(s);
                                }
                            }
                        }

//                        int length = xx.getRuns().size();
//                        for (int s = (length - 1); s >= 0; s--) {
//                            xx.removeRun(s);
//                        }

                        XWPFRun insertNewRun = xx.insertNewRun(0);
                        insertNewRun.setText(String.valueOf(map.get(arrText.get(i).toUpperCase())));
                        cellText.get(i).setParagraph(xx);

                    }
                }
            }

            if (map.containsKey(key)) {
                List<Map<String, String>> list = (List<Map<String, String>>) map.get(key);
                for (int i = 0; i < list.size(); i++) {
                    //XWPFTableRow row = table.getRow(startRowIndex + 1);

//                    table.insertNewTableRow(startRowIndex + 1 + i);
                    XWPFTableRow tmpRow = table.getRow(startRowIndex + 1 + i);

                    List<XWPFTableCell> cells = tmpRow.getTableCells();
                    for (int j = 0; j < arr.size(); j++) {
                        XWPFParagraph paragraph = paragraphs.get(j);
                        int length = paragraphs.get(j).getRuns().size();
                        for (int s = (length - 1); s >= 0; s--) {
                            paragraph.removeRun(s);
                        }
                        //paragraphs.get(j).removeRun(0);
                        XWPFRun insertNewRun = paragraphs.get(j).insertNewRun(0);
                        insertNewRun.setText(list.get(i).get(arr.get(j).toUpperCase()));
                        if (cells.size() <= j) {
                            XWPFTableCell cell = tmpRow.createCell();
                            cell.setParagraph(paragraphs.get(j));
                        } else {
                            cells.get(j).setParagraph(paragraphs.get(j));
                        }
                    }

                    table.addRow(tmpRow, startRowIndex + 3 + i);
                }
                table.removeRow(startRowIndex);
                table.removeRow(startRowIndex);
                table.removeRow(startRowIndex);
            }

        }
    }

    /**
     *
     * <b>功能</b>：处理Word模板中Table内容<br/>
     *
     * @param document
     *            XWPFDocument对象
     * @param map
     *            数据源
     */
    @SuppressWarnings("unchecked")
    public static void checkTables(XWPFDocument document, Map<String, Object> map) {
        Iterator<XWPFTable> it = document.getTablesIterator();
        while (it.hasNext()) {
            XWPFTable table = (XWPFTable) it.next();
            int startRowIndex = 0;
            int rcount = table.getNumberOfRows();
            String key = "";
            List<String> arr = new ArrayList<String>();
            //单元格中只取第一个段落
            List<XWPFParagraph> paragraphs = new ArrayList<XWPFParagraph>();
            for (int i = 0; i < rcount; i++) {
                XWPFTableRow row = table.getRow(i);
                List<XWPFTableCell> cells = row.getTableCells();

                for (XWPFTableCell cell : cells) {
                    if (cell.getText().indexOf("forEach") > -1) {
                        String find = "\\{(.*?)\\}";
                        key = getStrbyPattern(cell.getText(), find);
                        startRowIndex = i;
                        continue;
                    }

                    if (cell.getText().indexOf("#{") > -1) {
                        String find = "\\{" + key + ".(.*?)\\}";
                        String vCell = getStrbyPattern(cell.getText(), find);
                        paragraphs.add(cell.getParagraphs().get(0));
                        arr.add(vCell);
                    }

                }
            }

            if (map.containsKey(key)) {
                List<Map<String, String>> list = (List<Map<String, String>>) map.get(key);
                for (int i = 0; i < list.size(); i++) {
                    XWPFTableRow tmpRow = table.createRow();
                    List<XWPFTableCell> cells = tmpRow.getTableCells();
                    for (int j = 0; j < arr.size(); j++) {
                        XWPFParagraph paragraph=paragraphs.get(j);
                        int length = paragraphs.get(j).getRuns().size();
                        for (int s = (length - 1); s >= 0; s--) {
                            paragraph.removeRun(s);
                        }
                        //paragraphs.get(j).removeRun(0);
                        XWPFRun insertNewRun = paragraphs.get(j).insertNewRun(0);
                        insertNewRun.setText(list.get(i).get(arr.get(j)));
                        cells.get(j).setParagraph(paragraphs.get(j));
                    }
                }
                table.removeRow(startRowIndex);
                table.removeRow(startRowIndex);
                table.removeRow(startRowIndex);
            }

        }
    }

    /**
     * <b>功能</b>：占位符内容<br/>
     *
     * @param source 源字符串
     * @param find   正则表达式字符
     * @return 内容
     */
    public static String getStrbyPattern(String source, String find) {
        String returnStr = "";
        Pattern pattern = Pattern.compile(find);
        Matcher matcher = pattern.matcher(source);

        while (matcher.find()) {
            returnStr = matcher.group(1).trim();
        }

        return returnStr;
    }

    public static void replaceInPara(XWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            replaceInPara(para, params);
        }
    }

    /**
     * 替换段落里面的变量
     *
     * @param para   要替换的段落
     * @param params 参数
     */
    public static void replaceInPara(XWPFParagraph para, Map<String, Object> params) {
        List<XWPFRun> runs;
        Matcher matcher;
        if (matcher(para.getParagraphText()).find()) {
            runs = para.getRuns();

            int start = -1;
            int end = -1;
            String str = "";
            for (int i = 0; i < runs.size(); i++) {
                XWPFRun run = runs.get(i);
                String runText = run.toString();
                if ('$' == runText.charAt(0)&&'{' == runText.charAt(1)) {
                    start = i;
                }
                if ((start != -1)) {
                    str += runText;
                }
                if ('}' == runText.charAt(runText.length() - 1)) {
                    if (start != -1) {
                        end = i;
                        break;
                    }
                }
            }

            for (int i = start; i <= end; i++) {
                para.removeRun(i);
                i--;
                end--;
            }

            for (String key : params.keySet()) {
                if (str.equals(key)) {
                    String param = String.valueOf(params.get(key));
                    if (param.indexOf("\n")>-1) {
                        String[] texts = param.split("\n");
                        for (int i = 0; i < texts.length; i++) {
                            para.createRun().setText(texts[i]);
                            para.createRun().addCarriageReturn();
                        }
                    } else {
                        para.createRun().setText(param);
                    }
                }
            }


        }
    }

    /**
     * 替换表格里面的变量
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    public static void replaceInTable(XWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFTable> iterator = doc.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        List<XWPFParagraph> paras;
        while (iterator.hasNext()) {
            table = iterator.next();
            rows = table.getRows();
            for (XWPFTableRow row : rows) {
                cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    paras = cell.getParagraphs();
                    for (XWPFParagraph para : paras) {
                        replaceInPara(para, params);
                    }
                }
            }
        }
    }

    /**
     * 正则匹配字符串
     *
     * @param str
     * @return
     */
    private static Matcher matcher(String str) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }

    /**
     * 关闭输入流
     *
     * @param is
     */
    public static void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭输出流
     *
     * @param os
     */
    public static void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}
